package com.wangsd.web.api;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.util.SignUtils;
import com.wangsd.common.component.WeixinPayService;
import com.wangsd.common.component.WxPayServiceExt;
import com.wangsd.common.mq.MqSend;
import com.wangsd.common.socket.WebSocketServer;
import com.wangsd.common.utils.AliClientUtil;
import com.wangsd.common.utils.MD5Utils;
import com.wangsd.common.utils.PayUtil;
import com.wangsd.web.MyController;
import com.wangsd.web.face.entity.*;
import com.wangsd.web.face.service.*;
import com.wangsd.web.sys.entity.SysUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Api(value = "notify", tags = "支付回调")
@Controller
@RequestMapping("/open")
@Slf4j
public class OpenController extends MyController {

    @Value("${service.url}")
    private String notifyUrl;
    @Value("${service.authApiUrl}")
    private String authApiUrl;


    @Autowired
    DeviceService deviceService;
    @Autowired
    StoreService storeService;
    @Autowired
    MerchantService merchantService;
    @Autowired
    ServiceBusinessService serviceBusinessService;
    @Autowired
    TOrderService tOrderService;
    @Autowired
    WeixinPayService weixinPayService;
    @Autowired
    MqSend mqSend;

    /**************************************************************聚合扫码处理************************************/

    /**
     * 聚合扫码支付
     *
     * @return
     */
    @ApiOperation(value = "聚合码地址", notes = "聚合码地址", httpMethod = "GET")
    @RequestMapping(value = "/scanPayOrder", method = RequestMethod.GET)
    @ResponseBody
    public void scanPayOrder(@ApiParam(value = "设备编号", required = true) @RequestParam String deviceNo,
                             @ApiParam(value = "支付金额", required = true) @RequestParam Integer totalFee,
                             @ApiParam(value = "调用方式", required = true) @RequestParam Integer payWay,
                             @ApiParam(value = "会员价格", required = false) Integer memberFee,
                             @ApiParam(value = "会员电话", required = false) String phone,
                             @ApiParam(value = "重定向地址", required = false) String redirectUrl,
                             @ApiParam(value = "Access-Token", required = true) @RequestParam String accessToken,
                             @ApiParam(value = "商户订单号", required = true) @RequestParam String outTradeNo) {
        try {
            Map map = new HashMap();
            map.put("type", "scan-paying-notice");
            map.put("outTradeNo", outTradeNo);
            String message = JSON.toJSONString(map);
            WebSocketServer.sendInfo(message, deviceNo);
        } catch (IOException e) {
            log.info(deviceNo + ":socket 通信失败");
        }
        try {
            //判断订单是否重复扫码！！！
            response.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=utf-8");
            TOrder order = tOrderService.selectByOutTradeNo(outTradeNo);
            if (order != null) { //订单已存在
                response.getWriter().write("请不要重复扫码！");
                return;
            }
            if (payWay == 1) {//通用通第三方地址，跳转
                SysUser user = getUserInfo(accessToken);
                if (user == null) {
                    response.getWriter().write("设备登录异常，请重启设备！");
                    return;
                }
                if (StringUtils.isBlank(redirectUrl)) {
                    response.getWriter().write("操作异常，请重新扫码！");
                }
                //创建本地订单
                tOrderService.createScanPayOrder(deviceNo, totalFee, memberFee, phone, outTradeNo, null, 4, user.getId());
                //重定向第三方支付页面
                response.sendRedirect(redirectUrl);
            } else {//微信支付宝原生扫码
                String userAgent = request.getHeader("user-agent");

                if (userAgent != null && userAgent.contains("AlipayClient")) {//支付宝
                    //支付宝wap支付创建订单
                    String url = "/open/aliOrderPay?deviceNo=" + deviceNo + "&totalFee=" + totalFee + "&token=" + accessToken + "&outTradeNo=" + outTradeNo;
                    if (memberFee != null) {
                        url += "&memberFee=" + memberFee;
                    }
                    if (StringUtils.isNotBlank(phone)) {
                        url += "&phone=" + phone;
                    }
                    response.sendRedirect(url);
                } else if (userAgent != null && userAgent.contains("MicroMessenger")) {//微信
                    //获取微信授权
                    String url = "/open/authorize?deviceNo=" + deviceNo + "&totalFee=" + totalFee + "&state=&token=" + accessToken + "&outTradeNo=" + outTradeNo;
                    if (memberFee != null) {
                        url += "&memberFee=" + memberFee;
                    }
                    if (StringUtils.isNotBlank(phone)) {
                        url += "&phone=" + phone;
                    }
                    response.sendRedirect(url);
                } else {
                    //未知，请在微信支付宝中打开
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**************************************************************聚合扫码处理************************************/


    /**************************************************************支付宝扫码************************************/
    /**
     * 支付宝扫码支付
     */
    @GetMapping("/aliOrderPay")
    @ResponseBody
    public void orderPay(String deviceNo, Integer totalFee, Integer memberFee, String phone, String token, String outTradeNo) {
        try {
            AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
            //获取设备信息
            Device device = deviceService.selectByDeviceNo(deviceNo);
            //获取门店信息
            Store store = storeService.getById(device.getStoreId());
            //获取商户信息
            Merchant merchant = merchantService.getById(store.getMerchantId());
            //获取服务商信息
            ServiceBusiness business = serviceBusinessService.getById(device.getBusinessServiceId());


            //初始化支付宝SDK客户端
            CertAlipayRequest certAlipayRequest = AliClientUtil.initCertAlipayRequest(
                    business.getAliAppId(), business.getAliPrivateKey(), business.getAppCertPublicKey(), business.getAlipayCertPublicKey(), business.getAlipayRootCert());
            AlipayClient client = new DefaultAlipayClient(certAlipayRequest);

            AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
            model.setOutTradeNo(outTradeNo);
            Double dFee = (memberFee != null && memberFee > 0) ? (memberFee * 0.01) : (totalFee * 0.01);
            BigDecimal bg = new BigDecimal(dFee);
            DecimalFormat df1 = new DecimalFormat("0.00");
            String fee = df1.format(bg);
            model.setTotalAmount(fee);
            model.setSubject("服务费充值");
            model.setTerminalId(deviceNo);
            ExtendParams extendParams = new ExtendParams();
            extendParams.setSysServiceProviderId(business.getProviderId());
            model.setExtendParams(extendParams);
            model.setBody(phone);
            //回调地址
            String notify = notifyUrl + "/open/aliScanNotify";
            request.setNotifyUrl(notify);
            request.setApiVersion("1.0");
            request.setBizModel(model);
            request.putOtherTextParam("app_auth_token", merchant.getAliAuthToken());
            AlipayTradePrecreateResponse precreateResponse = client.certificateExecute(request);

            SysUser user = getUserInfo(token);
            tOrderService.createScanPayOrder(deviceNo, totalFee, memberFee, phone, outTradeNo, null, 2, user.getId());

            response.sendRedirect(precreateResponse.getQrCode());
        } catch (AlipayApiException | IOException e) {
            e.printStackTrace();
        }
    }


    @RequestMapping("/aliScanNotify")
    @ResponseBody
    public void aliScanNotify() {
        String str = "success";
        try {
            //获取支付宝POST过来反馈信息
            Map<String, String> maps = new HashMap<String, String>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
                }
                maps.put(name, valueStr);
            }
            String tradeStatus = maps.get("trade_status");
            String outTradeNo = maps.get("out_trade_no");
            String tradeNo = maps.get("trade_no");
            String receiptAmount = maps.get("receipt_amount");
            String realFee = maps.get("buyer_pay_amount");
            String gmtPayment = maps.get("gmt_payment");
            String sellerId = maps.get("seller_id");
            String phone = maps.get("body");
            TOrder order = tOrderService.selectByOutTradeNo(outTradeNo);
            if (order != null && order.getBusinessServiceId() != null) {
                ServiceBusiness business = serviceBusinessService.getById(order.getBusinessServiceId());
                //调用SDK验证签名
                boolean signVerified = AlipaySignature.rsaCertCheckV1(maps, business.getAlipayCertPublicKey(), "UTF-8", "RSA2");
                log.info("支付签名验证" + signVerified);
                if (signVerified) {
                    if (tradeStatus.equals("TRADE_SUCCESS")) {//订单支付成功
                        log.info("支付成功");
                        if (order != null && order.getOrderStatus() == 0) {//待支付状态
                            TOrder upOrder = new TOrder();
                            upOrder.setId(order.getId());
                            upOrder.setOrderStatus(1);
                            upOrder.setTransactionId(tradeNo);
                            upOrder.setTimeEnd(gmtPayment);
                            upOrder.setCouponFee(0L);
                            upOrder.setSettlementTotalFee((long) (Double.valueOf(receiptAmount) * 100));
                            upOrder.setRealPayFee((long) (Double.valueOf(realFee) * 100));
                            upOrder.setOpenid(sellerId);
                            tOrderService.saveOrUpdate(upOrder);

                            //发送店员收款消息推送
                            storeService.sendWxTempLateReceivables(order);

                            mqSend.sendCheckIsMember(order.getMerchantId(), null, null, phone, 2, order.getId(), "ALIPAY");

                            log.info("推送socket消息");
                            Map socket = new HashMap();
                            socket.put("outTradeNo", outTradeNo);
                            socket.put("status", true);
                            socket.put("type", "scan-success-notice");
                            String message = JSON.toJSONString(socket);
                            WebSocketServer.sendInfo(message, order.getDeviceNo());
                        }
                    }
                }
            }
        } catch (AlipayApiException | IOException e) {
            e.printStackTrace();
        } finally {
            try {
                response.getWriter().write(str);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**************************************************************支付宝扫码************************************/


    /**************************************************************通用通扫码回调************************************/
    @RequestMapping("/tytScanNotify")
    @ResponseBody
    public void tytScanNotify(@RequestBody(required = false) String requestBody) {
        String result = "SUCCESS";
        try {
            log.info("接收到的报文：" + requestBody);
            JSONObject object = JSONObject.parseObject(requestBody);
            Integer state = object.getInteger("state");
            if (state == 0) {//支付成功
                String upOrderId = object.getString("upOrderId");
                String outTradeNo = object.getString("lowOrderId");
                String payTime = object.getString("payTime");
                String payMoney = object.getString("payMoney");
                String sign = object.getString("sign");
                String phone = object.getString("attach");
                String type = object.getString("channelId");
                TOrder order = tOrderService.selectByOutTradeNo(outTradeNo);
                //支付中的订单，防止重复处理
                if (order != null && order.getOrderStatus() == 0) { //待支付状态
                    Merchant merchant = merchantService.getById(order.getMerchantId());
                    String mySign = MD5Utils.doSign(object, merchant.getPayKey());
                    if (sign.equals(mySign)) {
                        TOrder upOrder = new TOrder();
                        upOrder.setId(order.getId());
                        upOrder.setOrderStatus(1);
                        upOrder.setTransactionId(upOrderId);
                        upOrder.setTimeEnd(payTime);
                        upOrder.setTradeType("SCAN");//1微信扫码，2支付宝扫码
                        upOrder.setRealPayFee((long) (Double.valueOf(payMoney) * 100));
                        upOrder.setSettlementTotalFee((long) (Double.valueOf(payMoney) * 100));
                        upOrder.setCouponFee(0L);
                        tOrderService.saveOrUpdate(upOrder);

                        //发送店员收款消息推送
                        storeService.sendWxTempLateReceivables(order);

                        //处理注册会员相关信息
                        mqSend.sendCheckIsMember(order.getMerchantId(), null, null, phone, 2, order.getId(), "TYT");

                        Map socket = new HashMap();
                        socket.put("outTradeNo", outTradeNo);
                        socket.put("status", true);
                        socket.put("type", "scan-success-notice");
                        String message = JSON.toJSONString(socket);
                        WebSocketServer.sendInfo(message, order.getDeviceNo());


                    } else {
                        result = "FULL";
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.getWriter().write(result);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**************************************************************通用通扫码回调************************************/


    /**************************************************************微信扫码支付************************************/
    /**
     * 开放平台第三方平台代公众号授权
     */
    @GetMapping("/authorize")
    @ResponseBody
    public void authorize(String deviceNo, Integer totalFee, Integer memberFee, String phone, String state, String token, String outTradeNo) {


        //获取设备信息
        Device device = deviceService.selectByDeviceNo(deviceNo);
        //获取服务商信息
        ServiceBusiness business = serviceBusinessService.getById(device.getBusinessServiceId());
        //回调地址
        String from = notifyUrl + "/open/authorizeCallbak";
        from += "?totalFee=" + totalFee + "&token=" + token + "&outTradeNo=" + outTradeNo + "&deviceNo=" + deviceNo;
        if (memberFee != null) {
            from += "&memberFee=" + memberFee;
        }
        if (StringUtils.isNotBlank(phone)) {
            from += "&phone=" + phone;
        }
        try {
            String url = authApiUrl + "/api/open/authorize?appid=" + business.getWxAppId() + "&from=" + URLEncoder.encode(from, "UTF-8");
            response.sendRedirect(url);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * （第三方平台）代公众号网页授权回调
     *
     * @param appid
     * @param deviceNo
     * @param totalFee
     */
    @RequestMapping("/authorizeCallbak")
    public String authorizeCallbak(String openid, String appid, String phone, String state, String token, String deviceNo, Integer totalFee, Integer memberFee, String outTradeNo, Model model) {
        log.debug("JSAPI 回调授权");
        try {

            //获取设备信息
            Device device = deviceService.selectByDeviceNo(deviceNo);
            if (device == null) {
                model.addAttribute("msg", "设备信息异常");
                return "error";
            }
            //获取门店信息
            Store store = storeService.getById(device.getStoreId());
            if (store == null) {
                model.addAttribute("msg", "门店信息异常");
                return "error";
            }
            //获取商户信息
            Merchant merchant = merchantService.getById(store.getMerchantId());
            if (merchant == null) {
                model.addAttribute("msg", "商户信息异常");
                return "error";
            }

            ServiceBusiness business = serviceBusinessService.getById(device.getBusinessServiceId());
            if (business == null) {
                model.addAttribute("msg", "服务商信息异常");
                return "error";
            }
            WxPayServiceExt wxPayServiceExt = weixinPayService.getServiceExt(store.getCode(), merchant.getSubMchId());


            //创建微信预支付订单
            WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
            request.setDeviceInfo(device.getDeviceNo());
            request.setBody(store.getName() + "-购买商品");
            request.setOutTradeNo(outTradeNo);
            //优先使用会员价
            request.setTotalFee((memberFee != null && memberFee > 0) ? memberFee : totalFee);
            request.setSpbillCreateIp("127.0.0.1");
            request.setNotifyUrl(notifyUrl + "/open/wxScanNotify");
            request.setTradeType("JSAPI");
            request.setOpenid(openid);
            request.setAttach(phone);
            request.setSubAppId(merchant.getSubAppId());
            WxPayUnifiedOrderResult result = wxPayServiceExt.unifiedOrder(request);
            if (result.getReturnCode().equals("SUCCESS") && result.getResultCode().equals("SUCCESS")) {
                //创建本地预支付订单

                SysUser user = getUserInfo(token);
                if (user == null) {
                    model.addAttribute("msg", "请重新登录收银员账号");
                    return "error";
                }
                TOrder order = tOrderService.createScanPayOrder(deviceNo, totalFee, memberFee, phone, outTradeNo, openid, 1, user.getId());


                Map map = new HashMap();
                map.put("appId", result.getAppid());
                map.put("timeStamp", (System.currentTimeMillis() + "").substring(0, 10));
                map.put("nonceStr", System.currentTimeMillis() + "");
                map.put("package", "prepay_id=" + result.getPrepayId());
                map.put("signType", "MD5");
                map.put("sign", SignUtils.createSign(map, "MD5", business.getWxMchKey(), new String[0]));
                map.put("prepayId", result.getPrepayId());
                map.put("totalFee", (memberFee != null && memberFee > 0) ? memberFee : totalFee);
                map.put("storeName", store.getName());
                model.addAttribute("params", map);
            } else {
                model.addAttribute("msg", result.getErrCodeDes());
                return "error";
            }
        } catch (WxPayException e) {
            model.addAttribute("msg", e.getErrCodeDes());
            return "error";
        }
        return "pay";
    }

    @RequestMapping("/wxScanNotify")
    @ResponseBody
    public void wxScanNotify(@RequestBody(required = false) String requestBody) {
        String returnXml = "<xml>"
                + "<return_code><![CDATA[SUCCESS]]></return_code>"
                + "<return_msg><![CDATA[OK]]></return_msg>"
                + "</xml> ";
        try {
            log.info("接收到的报文：" + requestBody);
            Map map = PayUtil.doXMLParse(requestBody);
            String returnCode = (String) map.get("return_code");
            String resultCode = (String) map.get("result_code");
            //商户订单号
            String outTradeNo = (String) map.get("out_trade_no");
            String wxSign = (String) map.get("sign");
            String transactionId = (String) map.get("transaction_id");
            String timeEnd = (String) map.get("time_end");
            Long cashFee = Long.valueOf((String) map.get("cash_fee"));
            Long settlementTotalFee = null;
            if (map.get("settlement_total_fee") != null) {
                settlementTotalFee = Long.valueOf((String) map.get("settlement_total_fee"));
            }
            Long couponFee = 0L;
            if (map.get("coupon_fee") != null) {
                couponFee = Long.valueOf((String) map.get("coupon_fee"));
            }

            String subOpenId = (String) map.get("sub_openid");
            String subIsSubscribe = (String) map.get("sub_is_subscribe");
            String isSubscribe = (String) map.get("is_subscribe");
            String phone = map.get("attach") == null ? null : (String) map.get("attach");
            //检查执行结果
            if (WxPayConstants.ResultCode.SUCCESS.equals(returnCode)//执行结果成功
                    && WxPayConstants.ResultCode.SUCCESS.equals(resultCode)) {//业务结果成功
                TOrder order = tOrderService.selectByOutTradeNo(outTradeNo);

                //支付中的订单，防止重复处理
                if (order != null && order.getOrderStatus() == 0) {//待支付状态
                    ServiceBusiness business = serviceBusinessService.getById(order.getBusinessServiceId());
                    String mySign = SignUtils.createSign(map, "MD5", business.getWxMchKey(), new String[0]);
                    if (wxSign.equals(mySign)) {//签名验证成功
                        TOrder upOrder = new TOrder();
                        upOrder.setId(order.getId());
                        upOrder.setOrderStatus(1);
                        upOrder.setTransactionId(transactionId);
                        upOrder.setTimeEnd(timeEnd);
                        upOrder.setRealPayFee(cashFee);
                        upOrder.setSettlementTotalFee(settlementTotalFee == null || settlementTotalFee == 0 ? order.getMemberTotalFee() : settlementTotalFee);
                        upOrder.setCouponFee(couponFee);
                        tOrderService.saveOrUpdate(upOrder);

                        //发送店员收款消息推送
                        storeService.sendWxTempLateReceivables(order);

                        Integer isSend = StringUtils.isNotBlank(subIsSubscribe) && subIsSubscribe.equals("Y") ? 2
                                : StringUtils.isNotBlank(isSubscribe) && isSubscribe.equals("Y") ? 1 : 0;
                        //处理注册会员相关信息
                        mqSend.sendCheckIsMember(order.getMerchantId(), order.getOpenid(), subOpenId, phone, isSend, order.getId(), "WXPAY");

                        Map socket = new HashMap();
                        socket.put("outTradeNo", outTradeNo);
                        socket.put("status", true);
                        socket.put("type", "scan-success-notice");
                        String message = JSON.toJSONString(socket);
                        WebSocketServer.sendInfo(message, order.getDeviceNo());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.getWriter().write(returnXml);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**************************************************************微信扫码支付************************************/
}
